package com.xneure.database;

import java.lang.reflect.Method;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import com.xneure.code.msg.MessageListener;
import com.xneure.code.msg.MsgListener;
import com.xneure.database.dialect.SqlDialect;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.SpringUtil;

/**
 * <p>
 * 数据源动态切换工具
 * </p>
 * <p>
 * Copyright: 版权所有<br>
 *
 * @author zhangjun
 * @version 2017年3月13日
 */
public class DynamicDataSource extends AbstractRoutingDataSource{
	private static final ThreadLocal<DataSourceContext> currDataSource = new ThreadLocal<DataSourceContext>();

	public static SqlDialect getSqlDialect(){
		DataSource ds = DynamicDataSource.getDataSource().getLastDataSource();
		if(null == ds){
			ds = SpringUtil.getDataSource();
		}
		return getSqlDialect(ds);
	}

	public static SqlDialect getSqlDialect(DataSource ds){
		DataBaseType type = DataBaseType.identify(ds);
		return DataSourceContext.sqlDialect.get(type.getDbName());
	}

	@Override
	protected DataSource determineTargetDataSource(){
		DataSource determineTargetDataSource = super.determineTargetDataSource();
		getDataSource().setLastDataSource(determineTargetDataSource);
		return determineTargetDataSource;
	}

	static void setCurrMethod(Method method){
		getDataSource().setCurrMethod(method);
	}

	static Method getCurrMethod(){
		return getDataSource().getCurrMethod();
	}

	@Override
	protected Object determineCurrentLookupKey(){
		return getDataSource().getCurrDataSource();
	}

	public static String getCurrDataSource(){
		return getDataSource().getCurrDataSource();
	}

	public static void setCurrDataSource(String defDataSource){
		if(null != defDataSource){
			getDataSource().setCurrDataSource(defDataSource);
		}
	}

	public static DataSource geLastDataSource(){
		return getDataSource().getLastDataSource();
	}

	public static String getDataSourceInfo(){
		return getDataSource().getDataSourceInfo();
	}

	static DataSourceContext getDataSource(){
		DataSourceContext dataSourceContext = currDataSource.get();
		if(null == dataSourceContext){
			dataSourceContext = new DataSourceContext();
			currDataSource.set(dataSourceContext);
		}
		return dataSourceContext;
	}

	@MsgListener(DataSourceMsg.class)
	public MessageListener<DataSourceMsg> changeSource(){
		return new MessageListener<DataSourceMsg>(){
			@Override
			public void handler(DataSourceMsg msg,Enum<?> action){
				if(null == msg.getDataSourceName()){
					DynamicDataSource.getDataSource().setCurrDataSource(null).setLock(false);
				}else{
					if(null != msg.getDataSource()){
						addDataSources(msg.getDataSourceName(),msg.getDataSource());
					}
				}
			}
		};
	}

	private void addDataSources(String name,DataSource ds){
		Map<Object,Object> tds = ObjectUtil.getFieldValue(this,"targetDataSources");
		tds.put(name,ds);
		afterPropertiesSet();
	}
}
